package com.android.lovely.framework

import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingSource
import androidx.paging.PagingState
import androidx.paging.cachedIn
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.withContext

/**
 *
 * @author why
 * @date 2025/3/7 15:45
 */
abstract class BaseLoadViewModel<T : Any> : BaseViewModel() {
    private val _pageChangeFlow = MutableSharedFlow<Int>(0, 1, BufferOverflow.SUSPEND)
    val pageChangeFlow: SharedFlow<Int> get() = _pageChangeFlow

    var currentPage = 1
    fun getPageSize(): Int {
        return 10
    }

    val pager by lazy {
        Pager(PagingConfig(
            pageSize = getPageSize(),
            initialLoadSize = getPageSize(),
        ), pagingSourceFactory = { ViewModelPagingSource() }).flow.cachedIn(viewModelScope)
    }

    abstract suspend fun requestApi(page: Int, loadSize: Int): List<T>


    private inner class ViewModelPagingSource : BasePageSource<T>() {
        override suspend fun getResponse(page: Int, loadSize: Int): List<T> {
            this@BaseLoadViewModel.currentPage = page
            return requestApi(page, loadSize)
        }

        override fun dataChange(data: T) {

        }
    }

    private val _removedFlow = MutableStateFlow<MutableList<Int>>(mutableListOf())
    val removedFlow: StateFlow<MutableList<Int>> get() = _removedFlow

    fun remove(id: Int) {
        val removeIds = _removedFlow.value
        val list = mutableListOf(id)
        list.addAll(removeIds)
        _removedFlow.value = list
    }
}


abstract class BasePageSource<T : Any>() : PagingSource<Int, T>() {

    override fun getRefreshKey(state: PagingState<Int, T>): Int? {
        return 1
    }

    override val keyReuseSupported = true

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, T> {
        val offset = params.key ?: 1
        val loadSize = params.loadSize
        val result = runCatching { getResponse(offset, loadSize) }
        return if (result.isSuccess) {
            val data = result.getOrDefault(emptyList())
            val isLoadEnd = data.isEmpty() || data.size < loadSize
            val nextKey = if (isLoadEnd) null else offset + 1
            LoadResult.Page(data = data, prevKey = null, nextKey = nextKey)
        } else {
            val error = result.exceptionOrNull()
            LoadResult.Error(error ?: Throwable())
        }
    }

    abstract suspend fun getResponse(page: Int, loadSize: Int): List<T>
    abstract fun dataChange(data: T)

}